#%%
# 为了存储Python中的对象，必须先将其转换为字节，然后再将字节写入文件。
# 这个过程称为序列化，又叫作数据转换（marshaling）、压缩（deflating）或编码（encoding）

# Python对象主要保存在计算机内存中，它们的生命周期就是Python进程。
# 如果希望一个对象的生命周期超过Python进程或命名空间，我们需要将它持久化


# 集合设计时有3种选择：封装、扩展或新建

# 重复带来的优势是每行是独立的，并且不依赖于上下文，这个上下文是基于在它上面的行来定义的。

# 序列化和保存——"JSON、YAML、Pickle、CSV和XML”中使用的技术更偏向于处理单一的对象

# 持久化更大的域中的独立对象,  应用程序中通常在4种情况下会持久化对象，它们统称为CRUD操作：创建（Create）、获取（Retrieve）、更新（Update）和删除（Delete）
# 通常，它们中的任意一个操作都有可能应用于域中的任意对象，这就需要一个更复杂的持久化机制，而不是使用单一的负载机制或者全部保存到一个文件中

'''
All properties and methods are based on reality world
'''

# ACID属性描述了,我们期望的数据库事务的行为, 4个规则定义我们的预期
    # 原子性（Atomicity）：事务必须是原子的。如果事务中包括多个操作，那么所有的操作都必须全部完成或者全部取消。
    # 一致性（Consistency）：事务必须保证一致。它会将数据库从某个状态改变为另外一个状态。事务不应该破坏数据库或者导致同时在线的不同用户看到不一致的视图。
    # 隔离性（Isolation）：每个事务都应该正常运行，就好像他们是完全隔离的。不存在两个用户可以互相干扰对方更新的并发用户。
    # 持久性（Durability）：对数据库的改变必须是持久的，他们应该被正确地存储在文件系统中。

# shelve. sync()方法会在关闭之前保存改变
import shelve
from contextlib import closing
with closing( shelve.open('some_file', 'r') ) as shelf:
    process( shelf )

# 复杂的地方是SQL数据库没有直接支持保存复杂Python对象，这就带来了阻抗失配问题（impedance mismatch problem）

# MYSQL，可以作为独立的服务进程。
# SQLite不是独立的数据库服务，它必须作为宿主应用的一部分，而对于我们来说，Python就是宿主。

# 在SQL数据库中，我们主要侧重于数据模型的3个层面
    # 概念模型
        # 实体关系是基于 SQL 模型创建的
        # 可以映射为Python对象并且与应用中的数据层相对应
    # 逻辑模型
        # SQL数据库中的表、行、列
        # 在SQL数据操作语句中来处理这些实体
    # 物理模型
        # 文件、块、页、比特和用于物理存储的字节。
        # 这些实体由管理级别的SQL语句进行定义
        
# SQL语句可以被分为3类：
    # 数据定义语言（data definitionlanguage，DDL）
    # 数据操纵语言（data manipulation language，DML）
    # 数据控制语言（data control language，DCL）

# execute()函数的执行结果是一个游标对象。游标是可迭代的，它将迭代返回所有的行结果集

# decimal.Decimal并没有被SQLite直接支持，需要对SQLite进行扩展来处理这种类型的数据。
# 两种方式：转换和适配。我们需要对 Python 的数据进行适配，存入 SQLite需要将SQLite中的数据转换到Python中

    """
    傳輸和共享對象
    Transfer and share objects
    
表述性状态传输（Representational State Transfer，REST）
    当我们序列化对象时，实际上是在创建对象状态的表示，这种表示可以被传输到另外一个进程中（通常在另外一个主机上），
    另外一个进程可以根据这个状态的表示和一个本地定义的类来创建原始对象的对应版本
    
有很多种方式执行REST操作。
    其中一个方面是可以使用的状态表示；
    另外一个方面是控制传输过程的协议。
    """
# 对于本地进程间的通信，我们会介绍multiprocessing模块提供的本地消息队列。
# 对于互联网的传输，我们会用HTTP协议实现CRUD操作，这通常被称为REST服务器。我们也会介绍如何实现RESTful服务


"""
一个能将对象在不同进程间传输的方法，可以将一个大问题分解为两个更小的问题。

不同的网络协议可以帮我们将字节流从一个主机上的某个进程传输到另一台主机的某个进程中。

网络用于传输字节流。因此，我们必须用字节流表示一个对象实例中变量的值


两个步骤将对象转换为字节流
    首先用字符串表示一个对象的状态，
    然后基于这个字符串以某种标准的编码方式提供字节表示。
"""
# 超文本传输协议（Hypertext Transfer Protocol，HTTP）是由一系列的RFC（Request for Comments）文档定义的
"""
HTTP协议包括请求和响应。
一个请求包括一个方法、一个统一资源标识符（Uniform Resource Identifier，URI）、一些报头和可选的附件。
一个响应包含一个状态码、原因、一些报头和一些数据。

HTTP是无状态协议。
    服务器不会保留任何之前与客户端交互的信息，有很多方法可以克服这个限制。
    对于交互式网站，通过cookie来追踪事务状态并且改善程序行为。
"""

# 将应用程序的安全分为两个部分考虑：验证和授权
    # 知道用户是谁
    # 并且需要确保用户有运行某个WSGI应用程序的授权




# WSGI的目的是用一个相对简单并且容易扩展的Python API来将HTTP的请求响应处理过程标准化


"""
WSGI应用程序框架执行RESTful Web服务统一
    接收HTTP请求、
    反序列化对象、
    执行请求的功能、
    序列化结果
    并且提供响应的过程

由于WSGI应用程序的API简单、标准，因此我们可以很容易地创建复合应用程序和封装程序。


用multiprocessing将消息插入共享队列或者从共享队列中移除消息。
    使用消息队列的好处是我们可以避免并发更新共享对象所带来的锁问题。
"""

# 三种配置文件的使用场景
    # 需要编辑一个配置文件
    # 软件的一个部分需要读配置文件并使用选项和参数来修改它的行为
    # 在应用完成更新后将配置保存到一个文件

""" 
应用程序配置有两种核心的设计模式
    全局属性映射：使用一个全局的对象，它将包含所有的配置参数。
        它可以是name: value的映射对或是包含了属性值的对象。
        它将使用单例设计模式来确保只有一个实例
        # 通常情况下，我们避免使用全局变量。
        # 因为全局变量在程序的任何部分都是可见的，它可能会被忽视，可以使用对象的构造替代全局变量来更好地对配置进行处理。
    对象创建：不再使用单例，而是定义了工厂或是工厂的集合，基于配置数据来创建应用程序的对象。
        这样一来，配置信息只在程序启动时被使用一次。
        配置信息不会保存在全局的对象中。

"""

#%%
# 创建日志有两个必要的步骤
    # 通过logging.getLogger()函数获得logging.Logger实例
    # 用获得的Logger创建消息。创建不同重要性级别消息的方法，例如warn()、info()、debug()、error()和fatal()。
# 配置logging模块的handlers、filters和formatters，可以用logging.basicConfig()函数完成这些配置
import logging
logging.basicConfig()

In [50]: class P:
    ...:     def __init__(self):
    ...:         print(str(self.__class__.__qualname__))
    ...:     def __repr__(self):
    ...:         return f"{self.__module__}.{self.__class__.__qualname__}"
    ...:

In [51]: P()
P
Out[51]: __main__.P

#%%
# Here is one way to implement a switch construct
# Switcher is a dictionary data type here
def week(i):
    switcher={
        0:'Sunday',
        1:'Monday',
        2:'Tuesday',
        3:'Wednesday',
        4:'Thursday',
        5:'Friday',
        6:'Saturday'
    }
    return switcher.get(i,"Invalid day of week")

print(week(5)) # Call the function

# %%

